#pragma once

#include<QString>
#include<QIcon>
#include<QUuid>
#include<QDateTime>
#include<QFile>
#include<QDebug>
#include<QFileInfo>

#include"base.qpb.h"
#include"gateway.qpb.h"
#include"user.qpb.h"
#include"friend.qpb.h"
#include"file.qpb.h"
#include"notify.qpb.h"
#include"speech_recognition.qpb.h"
#include"message_storage.qpb.h"
#include"message_transmit.qpb.h"

//创建命名空间
namespace model{

//////////////////////////////////////////////////
////// 工具函数     后续很多模块可能会用到
//////////////////////////////////////////////////

//根据路径得到文件名
static inline QString getFileName(const QString& path){
    QFileInfo fileInfo(path);
    return fileInfo.fileName();
}

//封装一个"宏"作为打印日志的方式
#define TAG QString("[%1:%2]").arg(model::getFileName(__FILE__),QString::number(__LINE__))
//qDebug()打印会自动加上""
#define LOG() qDebug().noquote() << TAG

//要求的函数写在.h需要加上static或者inline,避免链接阶段出现函数“重定义”的问题
static inline QString formatTime(int64_t timestamp){
    //先把时间戳转换成QDateTime对象
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);

    //把QDateTime对象转换成"格式化时间" 月-日 时:分:秒
    return dateTime.toString("MM-dd HH::mm::ss");
}


//通过这个函数得到秒级的时间戳
static inline int64_t getTime(){
    return QDateTime::currentSecsSinceEpoch();
}

//根据QByteArray转成QIcon
static inline QIcon makeIcon(const QByteArray& byteArray){
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon(pixmap);
    return icon;
}

//读写操作
//从指定文件中读取一个二进制文件，得到QByteArray
static inline QByteArray loadFiletoByteArray(const QString& path){
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok){
        qDebug() << "打开文件失败！";
        return QByteArray();
    }
    QByteArray content = file.readAll();
    file.close();
    return content;
}

//将QByteArray写入到指定文件中
static inline void writeByteArraytoFile(const QByteArray& content , const QString& path){
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok){
        qDebug() << "打开文件失败！";
        return ;
    }
    file.write(content);
    file.flush();
    file.close();
}



//////////////////////////////////////////////////
////// 用户信息
//////////////////////////////////////////////////

class UserInfo{
public:
    QString userId = "";					//用户编号
    QString nickname = ""; 					//用户昵称
    QString description = "";				//用户签名
    QString phone = "";						//手机号码
    QIcon avatar;							//用户头像

    //从protobuffer的UserInfo对象转换成当前代码的UserInfo对象
    void load(const bite_im::UserInfo& userInfo){
        this->userId = userInfo.userId();
        this->description = userInfo.description();
        this->nickname = userInfo.nickname();
        this->phone = userInfo.phone();
        if(userInfo.avatar().isEmpty()){
            //使用默认头像
            this->avatar = QIcon(":/resource/image/defaultAvatar.png");
        }
        else{
            this->avatar = makeIcon(userInfo.avatar());
        }
    }

};

/////////////////////////////////////////////////
////// 消息信息
/////////////////////////////////////////////////
enum MessageType{
    TEXT_TYPE,				//文本消息
    IMAGE_TYPE,				//图片消息
    FILE_TYPE,				//文件消息
    SPEECH_TYPE   			//语音消息
};



class Message{
public:
    QString messageId = "";						//消息的编号
    QString chatSessionId = "";					//消息所属会话的编号
    QString time = "";							//消息的时间，通过"格式化"时间的方式来表示，形如06-07 12:00:00
    MessageType messageType;					//消息的类型
    UserInfo sender;							//发送者的信息
    QByteArray content;							//消息的正文内容
    QString fileId = "";						//文件的身份标识，当消息类型为文件，图片，语音的时候才有效，当文件类型为文本，则为""
    QString fileName = "";						//文件名称，只有当消息类型为文件消息才有效，其他消息均为""

    //从protobuffer的Message对象转换成当前代码的Message对象
    void load(const bite_im::MessageInfo& messageInfo){
        this->messageId = messageInfo.messageId();
        this->chatSessionId = messageInfo.chatSessionId();
        this->time = formatTime(messageInfo.timestamp());
        this->sender.load(messageInfo.sender());

        auto type = messageInfo.message().messageType();
        if(type == bite_im::MessageTypeGadget::MessageType::STRING){
            this->messageType = TEXT_TYPE;
            this->content = messageInfo.message().stringMessage().content().toUtf8();
        }
        else if(type == bite_im::MessageTypeGadget::MessageType::IMAGE){
            this->messageType = IMAGE_TYPE;
            if(messageInfo.message().imageMessage().hasImageContent()){
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if(messageInfo.message().imageMessage().hasFileId()){
                this->fileId = messageInfo.message().imageMessage().fileId();
            }
        }
        else if(type == bite_im::MessageTypeGadget::MessageType::SPEECH){
            this->messageType = SPEECH_TYPE;
            if(messageInfo.message().speechMessage().hasFileContents()){
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if(messageInfo.message().speechMessage().hasFileId()){
                this->fileId = messageInfo.message().speechMessage().fileId();
            }
        }
        else if(type == bite_im::MessageTypeGadget::MessageType::FILE){
            this->messageType = FILE_TYPE;
            if(messageInfo.message().fileMessage().hasFileContents()){
                this->content = messageInfo.message().fileMessage().fileContents();
            }
            if(messageInfo.message().fileMessage().hasFileId()){
                this->fileId = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();
        }
        else{
            //类型错误，输出错误信息
            LOG() << "类型错误！Type=" << type;
        }

    }


    //工厂模式
    //此处的 extraInfo 目前只是在消息类型为文件消息时，作为"文件名的补充"
    static Message makeMessage(MessageType messageType , const QString& chatSessionId , const UserInfo& sender ,
                               const QByteArray& content , const QString& extraInfo){
        if(messageType == TEXT_TYPE){
            return makeTextMessage(chatSessionId , sender , content);
        }
        else if(messageType == IMAGE_TYPE){
            return makeImageMessage(chatSessionId , sender , content);
        }
        else if(messageType == FILE_TYPE){
            return makeFileMessage(chatSessionId , sender , content);
        }
        else if(messageType == SPEECH_TYPE){
            return makeSpeechMessage(chatSessionId , sender , content);
        }
        else{
            //触发了未知类型的消息
            return Message();
        }
    }

private:
    //通过这个方法生成唯一的messagId
    static QString makemessageId(){
        return "M" + QUuid::createUuid().toString().sliced(25,12);
    }

    //工厂构造方法
    static Message makeTextMessage(const QString& chatSessionId , const UserInfo& sender , const QByteArray& content){
        Message message;
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.content = content;
        message.messageType = TEXT_TYPE;
        //此处需要保证设置的messageId在所有消息中都是唯一的
        message.messageId = makemessageId();
        //生成一个格式化的时间
        message.time = formatTime(getTime());

        //对于文本消息，这两属性不使用，设置为""
        message.fileId = "";
        message.fileName = "";

        return message;
    }
    static Message makeImageMessage(const QString& chatSessionId , const UserInfo& sender , const QByteArray& content){

        Message message;
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.content = content;
        message.messageType = IMAGE_TYPE;
        //此处需要保证设置的messageId在所有消息中都是唯一的
        message.messageId = makemessageId();
        //生成一个格式化的时间
        message.time = formatTime(getTime());

        //对于图片消息，fileId后续使用时再进一步设置
        message.fileId = "";
        //fileNname不使用，设置为""
        message.fileName = "";

        return message;
    }
    static Message makeFileMessage(const QString& chatSessionId , const UserInfo& sender , const QByteArray& content){

        Message message;
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.content = content;
        message.messageType = FILE_TYPE;
        //此处需要保证设置的messageId在所有消息中都是唯一的
        message.messageId = makemessageId();
        //生成一个格式化的时间
        message.time = formatTime(getTime());

        //对于文件消息fileId，后续使用再设置
        message.fileId = "";
        message.fileName = "";

        return message;
    }

    static Message makeSpeechMessage(const QString& chatSessionId , const UserInfo& sender , const QByteArray& content){

        Message message;
        message.chatSessionId = chatSessionId;
        message.sender = sender;
        message.content = content;
        message.messageType = SPEECH_TYPE;
        //此处需要保证设置的messageId在所有消息中都是唯一的
        message.messageId = makemessageId();
        //生成一个格式化的时间
        message.time = formatTime(getTime());

        //对于语音消息，fileId后续使用再设置
        message.fileId = "";
        //fileName不使用，直接设置为""
        message.fileName = "";

        return message;
    }


};


////////////////////////////////
/// 会话信息
///////////////////////////////
class ChatSessionInfo{
public:
    QString chatSessionId = "";  				//会话编号
    QString chatSessionName = ""; 				//会话名字，如果会话是单聊，名字就是对方的昵称；如果是群聊，名字就是群聊的名称，
    Message lastMessage;						//表示最新的消息
    QIcon avator; 								//会话头像，如果会话是单聊，头像就是对方的头像；如果是群聊，头像就是群聊的头像,
   QString userId = "";							//对于单聊，设置为对方用户的Id,对于群聊设为""

    //从protobuffer的Message对象转换成当前代码的Message对象
    void load(const bite_im::ChatSessionInfo& chatSessionInfo){
        this->chatSessionId = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();
        if(chatSessionInfo.hasPrevMessage()){
            this->lastMessage.load(chatSessionInfo.prevMessage());
        }
        if(chatSessionInfo.hasSingleChatFriendId()){
            this->userId = chatSessionInfo.singleChatFriendId();
        }
        if(chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty()){
            //已经有头像了，直接设置
            this->avator = makeIcon(chatSessionInfo.avatar());
        }
        else{
            //没有头像，根据当前会话是单聊还是群聊，设置默认头像
            if(userId != ""){
                //单聊
                this->avator = QIcon(":/resource/image/defaultAvatar.png");
            }
            else{
                //群聊
                this->avator = QIcon(":/resource/image/groupAvatar.png");
            }
        }

    }
};


}//end model
